#include "serializer/serializer.h"

#include <gtest/gtest.h>

#include <memory>
#include <string>
#include <vector>

using namespace serializer;

/**
 * 通用往返序列化工具函数
 * 参数:
 * - value 输入值
 * - options 序列化选项
 * 返回值: 反序列化结果
 * 异常: 序列化/反序列化失败时抛出异常
 */
template <typename T>
T
roundtrip_via_cpo(const T & value, const default_options & options)
{
    vector_writer writer;
    serialize(writer, value, options);
    vector_reader reader(writer.data());
    return deserialize_cpo(reader, options, type_tag<T>);
}

// 用于测试的自定义类型
struct test_data_struct
{
    int id;
    std::string name;
    double value;

    bool operator==(const test_data_struct & other) const
    {
        return id == other.id && name == other.name && value == other.value;
    }
};

// 为自定义类型实现 tag_invoke
template <typename Writer,
          typename Options,
          typename std::enable_if<writer<Writer> && serialization_options<Options>, int>::type = 0>
void
tag_invoke(serialize_tag_t, Writer & writer, const test_data_struct & data, const Options & options)
{
    serialize(writer, data.id, options);
    serialize(writer, data.name, options);
    serialize(writer, data.value, options);
}

template <typename Reader,
          typename Options,
          typename std::enable_if<reader<Reader> && serialization_options<Options>, int>::type = 0>
test_data_struct
tag_invoke(deserialize_tag_t<test_data_struct>, Reader & reader, const Options & options)
{
    auto id = deserialize_cpo(reader, options, type_tag<int>);
    auto name = deserialize_cpo(reader, options, type_tag<std::string>);
    auto value = deserialize_cpo(reader, options, type_tag<double>);
    return {id, name, value};
}

TEST(cpo_smart_pointers_test, unique_ptr_basic_types)
{
    default_options options{};

    // 测试 unique_ptr<int>
    auto ptr_int = std::make_unique<int>(42);
    auto result_int = roundtrip_via_cpo(ptr_int, options);

    ASSERT_TRUE(result_int != nullptr);
    EXPECT_EQ(*result_int, 42);

    // 测试 unique_ptr<string>
    auto ptr_string = std::make_unique<std::string>("Hello, unique_ptr!");
    auto result_string = roundtrip_via_cpo(ptr_string, options);

    ASSERT_TRUE(result_string != nullptr);
    EXPECT_EQ(*result_string, "Hello, unique_ptr!");

    // 测试 unique_ptr<double>
    auto ptr_double = std::make_unique<double>(3.14159);
    auto result_double = roundtrip_via_cpo(ptr_double, options);

    ASSERT_TRUE(result_double != nullptr);
    EXPECT_DOUBLE_EQ(*result_double, 3.14159);
}

TEST(cpo_smart_pointers_test, unique_ptr_nullptr)
{
    default_options options{};

    // 测试空 unique_ptr
    std::unique_ptr<int> null_ptr = nullptr;
    auto result = roundtrip_via_cpo(null_ptr, options);

    EXPECT_TRUE(result == nullptr);
    EXPECT_FALSE(result);
}

TEST(cpo_smart_pointers_test, unique_ptr_custom_type)
{
    default_options options{};

    // 测试自定义类型的 unique_ptr
    auto ptr_custom =
        std::make_unique<test_data_struct>(test_data_struct{123, "test_object", 99.99});
    auto result_custom = roundtrip_via_cpo(ptr_custom, options);

    ASSERT_TRUE(result_custom != nullptr);
    EXPECT_EQ(result_custom->id, 123);
    EXPECT_EQ(result_custom->name, "test_object");
    EXPECT_DOUBLE_EQ(result_custom->value, 99.99);
    EXPECT_EQ(*result_custom, *ptr_custom);
}

TEST(cpo_smart_pointers_test, unique_ptr_container_types)
{
    default_options options{};

    // 测试 unique_ptr<vector>
    auto ptr_vector = std::make_unique<std::vector<int>>(std::vector<int>{1, 2, 3, 4, 5});
    auto result_vector = roundtrip_via_cpo(ptr_vector, options);

    ASSERT_TRUE(result_vector != nullptr);
    EXPECT_EQ(result_vector->size(), 5);
    for (size_t i = 0; i < 5; ++i)
    {
        EXPECT_EQ((*result_vector)[i], static_cast<int>(i + 1));
    }
}

TEST(cpo_smart_pointers_test, shared_ptr_basic_types)
{
    default_options options{};

    // 测试 shared_ptr<int>
    auto ptr_int = std::make_shared<int>(777);
    auto result_int = roundtrip_via_cpo(ptr_int, options);

    ASSERT_TRUE(result_int != nullptr);
    EXPECT_EQ(*result_int, 777);

    // 测试 shared_ptr<string>
    auto ptr_string = std::make_shared<std::string>("Hello, shared_ptr!");
    auto result_string = roundtrip_via_cpo(ptr_string, options);

    ASSERT_TRUE(result_string != nullptr);
    EXPECT_EQ(*result_string, "Hello, shared_ptr!");
}

TEST(cpo_smart_pointers_test, shared_ptr_nullptr)
{
    default_options options{};

    // 测试空 shared_ptr
    std::shared_ptr<int> null_ptr = nullptr;
    auto result = roundtrip_via_cpo(null_ptr, options);

    EXPECT_TRUE(result == nullptr);
    EXPECT_FALSE(result);
    EXPECT_EQ(result.use_count(), 0);
}

TEST(cpo_smart_pointers_test, shared_ptr_custom_type)
{
    default_options options{};

    // 测试自定义类型的 shared_ptr
    auto ptr_custom =
        std::make_shared<test_data_struct>(test_data_struct{456, "shared_test", 123.45});
    auto result_custom = roundtrip_via_cpo(ptr_custom, options);

    ASSERT_TRUE(result_custom != nullptr);
    EXPECT_EQ(result_custom->id, 456);
    EXPECT_EQ(result_custom->name, "shared_test");
    EXPECT_DOUBLE_EQ(result_custom->value, 123.45);
    EXPECT_EQ(*result_custom, *ptr_custom);
}

TEST(cpo_smart_pointers_test, shared_ptr_reference_semantics)
{
    default_options options{};

    // 测试 shared_ptr 的引用计数语义（序列化后应该创建新的独立对象）
    auto original = std::make_shared<int>(888);
    auto copy = original; // 引用计数为 2

    EXPECT_EQ(original.use_count(), 2);
    EXPECT_EQ(copy.use_count(), 2);

    auto result = roundtrip_via_cpo(original, options);

    ASSERT_TRUE(result != nullptr);
    EXPECT_EQ(*result, 888);
    EXPECT_EQ(result.use_count(), 1);        // 新创建的对象，引用计数为 1
    EXPECT_NE(result.get(), original.get()); // 不同的内存地址
}

TEST(cpo_smart_pointers_test, smart_ptr_edge_cases)
{
    default_options options{};

    // 测试包含特殊值的智能指针
    auto ptr_zero = std::make_unique<int>(0);
    auto result_zero = roundtrip_via_cpo(ptr_zero, options);
    ASSERT_TRUE(result_zero != nullptr);
    EXPECT_EQ(*result_zero, 0);

    // 测试负数
    auto ptr_negative = std::make_shared<int>(-12345);
    auto result_negative = roundtrip_via_cpo(ptr_negative, options);
    ASSERT_TRUE(result_negative != nullptr);
    EXPECT_EQ(*result_negative, -12345);

    // 测试空字符串
    auto ptr_empty_string = std::make_unique<std::string>("");
    auto result_empty_string = roundtrip_via_cpo(ptr_empty_string, options);
    ASSERT_TRUE(result_empty_string != nullptr);
    EXPECT_TRUE(result_empty_string->empty());
}

TEST(cpo_smart_pointers_test, mixed_smart_pointers)
{
    default_options options{};

    // 测试混合使用不同类型的智能指针
    auto unique_int = std::make_unique<int>(100);
    auto shared_string = std::make_shared<std::string>("mixed test");
    auto unique_custom =
        std::make_unique<test_data_struct>(test_data_struct{999, "final_test", 0.001});

    // 分别序列化
    auto result_unique = roundtrip_via_cpo(unique_int, options);
    auto result_shared = roundtrip_via_cpo(shared_string, options);
    auto result_custom = roundtrip_via_cpo(unique_custom, options);

    // 验证结果
    ASSERT_TRUE(result_unique != nullptr);
    EXPECT_EQ(*result_unique, 100);

    ASSERT_TRUE(result_shared != nullptr);
    EXPECT_EQ(*result_shared, "mixed test");

    ASSERT_TRUE(result_custom != nullptr);
    EXPECT_EQ(result_custom->id, 999);
    EXPECT_EQ(result_custom->name, "final_test");
    EXPECT_DOUBLE_EQ(result_custom->value, 0.001);
}

TEST(cpo_smart_pointers_test, smart_ptr_exception_safety)
{
    default_options options{};

    // 测试异常安全性 - 确保在序列化/反序列化过程中不会泄漏内存
    try
    {
        auto ptr = std::make_unique<std::vector<int>>(1000000, 42); // 大对象
        auto result = roundtrip_via_cpo(ptr, options);

        ASSERT_TRUE(result != nullptr);
        EXPECT_EQ(result->size(), 1000000);
        EXPECT_EQ(result->front(), 42);
        EXPECT_EQ(result->back(), 42);
    }
    catch (const std::exception & e)
    {
        // 如果发生异常，测试应该失败，但不应该导致内存泄漏
        FAIL() << "Exception during smart pointer serialization: " << e.what();
    }
}

TEST(cpo_smart_pointers_test, smart_ptr_polymorphic_behavior)
{
    default_options options{};

    // 测试智能指针的多态行为（虽然我们的序列化不支持多态，但测试基本行为）
    struct base_type
    {
        int value = 42;
        virtual ~base_type() = default;

        bool operator==(const base_type & other) const { return value == other.value; }
    };

    // 为 base_type 实现序列化
    auto serialize_base = [](auto & writer, const base_type & obj, const auto & opts)
    { serialize(writer, obj.value, opts); };

    auto deserialize_base = [](auto & reader, const auto & opts) -> base_type
    {
        auto value = deserialize_cpo(reader, opts, type_tag<int>);
        base_type result;
        result.value = value;
        return result;
    };

    // 注意：这里我们不能直接使用 tag_invoke，因为它需要在全局作用域定义
    // 这个测试主要是为了验证智能指针本身的行为
    auto ptr = std::make_unique<base_type>();
    ptr->value = 123;

    // 手动序列化测试
    vector_writer writer;
    serialize_base(writer, *ptr, options);

    vector_reader reader(writer.data());
    auto deserialized_obj = deserialize_base(reader, options);

    EXPECT_EQ(deserialized_obj.value, 123);
}